package com.zmn.oms.third.pinduoduo.service.impl;

import com.alibaba.dubbo.rpc.RpcException;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.zmn.base.common.data.common.dro.area.AreaDRO;
import com.zmn.base.common.data.dubbo.interfaces.area.AreaListRemoteService;
import com.zmn.base.product.common.dto.product.ec.ProductBaseDRO;
import com.zmn.base.product.dubbo.interfaces.channel.product.third.ChannelProductThirdListRemoteService;
import com.zmn.common.constant.GlobalConsts;
import com.zmn.common.constant.StatusConsts;
import com.zmn.common.dictionary.GlobalDict;
import com.zmn.common.dto2.ResponseDTO;
import com.zmn.common.utils.collection.CollectionUtil;
import com.zmn.common.utils.date.DateUtil;
import com.zmn.common.utils.math.MoneyUtil;
import com.zmn.consts.GateTypeConsts;
import com.zmn.oms.business.interfaces.baidumap.BaiduMapBService;
import com.zmn.oms.business.interfaces.log.OrderLogBService;
import com.zmn.oms.business.interfaces.notifylog.OrderNotifyLogBService;
import com.zmn.oms.business.interfaces.remark.OrderRemarkBService;
import com.zmn.oms.business.interfaces.third.PinDuoDuoSignShopService;
import com.zmn.oms.business.interfaces.track.OrderTrackBService;
import com.zmn.oms.common.constant.OrderConsts;
import com.zmn.oms.common.constant.OrderLogConsts;
import com.zmn.oms.common.constant.OrderStatusConsts;
import com.zmn.oms.common.dto.ResultDTO;
import com.zmn.oms.common.exception.OmsBaseException;
import com.zmn.oms.model.bo.order.OrderBO;
import com.zmn.oms.model.dto.baidumap.LngLatLocation;
import com.zmn.oms.model.dto.factory.OrderFactoryDTO;
import com.zmn.oms.model.dto.order.proxy.CancelOrderDTO;
import com.zmn.oms.model.dto.order.zmn.FactoryNewOrderDTO;
import com.zmn.oms.model.entity.changerecord.OrderChangeRecord;
import com.zmn.oms.model.entity.log.OrderLog;
import com.zmn.oms.model.entity.notifylog.OrderNotifyLog;
import com.zmn.oms.model.entity.third.PinDuoDuoSignShop;
import com.zmn.oms.model.entity.track.OrderTrackQuery;
import com.zmn.oms.model.entity.work.OrderWork;
import com.zmn.oms.model.entity.work.OrderWorkLogChange;
import com.zmn.oms.model.vo.remark.OrderRemarkDetailVO;
import com.zmn.oms.model.vo.remark.OrderRemarkVO;
import com.zmn.oms.model.vo.work.ZsOrderWorkVO;
import com.zmn.oms.services.interfaces.changerecord.OrderChangeRecordService;
import com.zmn.oms.services.interfaces.detail.OrderDetailService;
import com.zmn.oms.services.interfaces.work.OrderWorkService;
import com.zmn.oms.third.base.util.MasterPhoneUtil;
import com.zmn.oms.third.pinduoduo.PinDuoDuoConsts;
import com.zmn.oms.third.pinduoduo.PinDuoDuoMapper;
import com.zmn.oms.third.pinduoduo.dto.PinDuoDuoAcceptOrderDTO;
import com.zmn.oms.third.pinduoduo.dto.PinDuoDuoShopExamineDTO;
import com.zmn.oms.third.pinduoduo.dto.api.*;
import com.zmn.oms.third.pinduoduo.service.PinDuoDuoService;
import com.zmn.oms.third.pinduoduo.util.PinDuoDuoUtil;
import com.zmn.oms.zmn.business.interfaces.proxy.ProxyOrderBService;
import com.zmn.oms.zmn.business.interfaces.work.ZsOrderWorkQueryBService;
import com.zmn.oms.zmn.business.interfaces.work.autoflow.WorkFlowContextBService;
import com.zmn.oms.zmn.normal.business.interfaces.order.FactoryOrderBService;
import io.netty.util.internal.StringUtil;
import io.shardingsphere.core.keygen.DefaultKeyGenerator;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * 类描述：拼多多服务接口调用实现类
 *
 * @author wangxiaokun
 * @since 2020/5/29 15:49
 */
@Service
@Slf4j
public class PinDuoDuoServiceImpl implements PinDuoDuoService {

//    @Reference(version = com.zmn.base.plat.engine.common.constant.DubboConsts.INTERFACE_VERSION , check = false)
//    private FactoryApplyModifyRemoteService factoryApplyModifyRemoteService;
//    @Reference(version = com.zmn.base.plat.engine.common.constant.DubboConsts.INTERFACE_VERSION , check = false)
//    protected DocumentaryContentListRemoteService documentaryContentListRemoteService;
    @Reference(version = com.zmn.base.plat.engine.common.constant.DubboConsts.INTERFACE_VERSION , check = false)
    protected AreaListRemoteService areaListRemoteService;
    @Reference(version = com.zmn.base.plat.engine.common.constant.DubboConsts.INTERFACE_VERSION , check = false)
    protected ChannelProductThirdListRemoteService channelProductThirdListRemoteService;

    @Autowired
    protected ZsOrderWorkQueryBService zsOrderWorkQueryBService;
    @Autowired
    private ProxyOrderBService proxyOrderBService;
    @Autowired
    private OrderNotifyLogBService orderNotifyLogBService;
    @Autowired
    protected OrderWorkService orderWorkService;
    @Autowired
    protected OrderDetailService orderDetailService;
    @Autowired
    protected WorkFlowContextBService workFlowContextBService;
    @Autowired
    protected OrderChangeRecordService orderChangeRecordService;
    @Autowired
    protected FactoryOrderBService factoryOrderBService;
    @Autowired
    protected PinDuoDuoSignShopService pinDuoDuoSignShopService;
    @Autowired
    DefaultKeyGenerator defaultKeyGenerator;
    @Autowired
    private OrderRemarkBService orderRemarkBService;
    @Autowired
    private OrderLogBService orderLogBService;
    @Autowired
    private OrderTrackBService orderTrackBService;
    @Autowired
    private BaiduMapBService baiduMapBService;

    /**
     * 处理拼多多发送的订单消息（店铺签约，创建订单，预约通知，取消订单等）
     * @param paramsStr 
     * @return com.zmn.oms.third.pinduoduo.dto.api.PinDuoDuoResponse
     * @author wangxiaokun
     */
    @Override
    public PinDuoDuoResponse handleSyncOrderMsg(String paramsStr) throws OmsBaseException {

        // 判断拼多多渠道开关
        if (!PinDuoDuoConsts.POWER_ON){
            throw new OmsBaseException(PinDuoDuoConsts.ZMN_RETURN_CODE_PARAM_ERROR, "拼多多接入渠道暂不支持");
        }

        if (Objects.isNull(paramsStr)){
            throw new OmsBaseException(PinDuoDuoConsts.ZMN_RETURN_CODE_PARAM_ERROR, "参数为空");
        }

        JSONObject jsonObject = JSONObject.parseObject(paramsStr);
        // 验证签名
        if (!PinDuoDuoUtil.verifyRequestSign(paramsStr)){
            throw new OmsBaseException(PinDuoDuoConsts.ZMN_RETURN_CODE_PARAM_ERROR, "签名验证失败");
        }

        PinDuoDuoResponse pinDuoDuoResponse = new PinDuoDuoResponse();
        pinDuoDuoResponse.setSuccess(true);
        pinDuoDuoResponse.setErrorCode(PinDuoDuoConsts.ZMN_RETURN_CODE_SUCCESS);
        pinDuoDuoResponse.setErrorMsg("success");

        // 根据请求type不同进行处理
        switch (jsonObject.get("type").toString()){
            case PinDuoDuoConsts.PDD_SERVICE_AFTERSALES_SIGN_FLAG:
                this.parseSignRequest(jsonObject.get("request").toString());
                break;
            case PinDuoDuoConsts.PDD_SERVICE_AFTERSALES_ORDER_PUSH_FLAG:
                this.parseCreateOrderRequest(jsonObject.get("request").toString());
                break;
            case PinDuoDuoConsts.PDD_SERVICE_AFTERSALES_APPOINT_NOTY_FLAG:
                this.parseAppointNotify(jsonObject.get("request").toString());
                break;
            case PinDuoDuoConsts.PDD_SERVICE_AFTERSALES_ORDER_CACEL_FLAG:
                this.parseCancelOrderRequest(jsonObject.get("request").toString());
                break;
            default:
                 throw new OmsBaseException(PinDuoDuoConsts.ZMN_RETURN_CODE_PARAM_ERROR, "参数错误");
        }
        return pinDuoDuoResponse;
    }

    /**
     * 同步接单信息到拼多多服务
     * @param orderWorkLogChange 
     * @return void
     * @author wangxiaokun
     */
    @Override
    public void sendAcceptOrderToPinDuoDuo(OrderWorkLogChange orderWorkLogChange) throws OmsBaseException {

        // 参数判断
        if (Objects.isNull(orderWorkLogChange)) {
            log.error("[{}]同步接单失败：参数为空", PinDuoDuoConsts.CHANNEL_NAME);
            return;
        }

        // 查看同步记录，对已经同步接单成功的，不需要再次同步
        if (this.findSuccessSyncResult(orderWorkLogChange, OrderStatusConsts.ORDER_STATUS_INPUT)) {
            return;
        }

        // 判断外部订单
        String outerId = orderWorkLogChange.getOuterId();
        if (StringUtil.isNullOrEmpty(outerId)) {
            log.error("[{}]同步接单失败：没有对应的外部订单Id", PinDuoDuoConsts.CHANNEL_NAME);
            return;
        }

        PinDuoDuoAcceptOrderDTO pinDuoDuoAcceptOrderDTO = new PinDuoDuoAcceptOrderDTO();
        pinDuoDuoAcceptOrderDTO.setBizStatus(PinDuoDuoConsts.PDD_ACCEPT_ORDER);
        pinDuoDuoAcceptOrderDTO.setServOrderSn(outerId);
        pinDuoDuoAcceptOrderDTO.setExecuteTime(DateUtil.toString(DateUtil.getNow(), "yyyy-MM-dd HH:mm:ss"));

        // 发送http请求
        String paramJson = JSON.toJSONString(pinDuoDuoAcceptOrderDTO, SerializerFeature.SortField.MapSortField);

        // 发送消息
        PinDuoDuoResponse responseRequest = sendRequestToPinDuoDuo(PinDuoDuoConsts.PDD_SERVICE_PATH, paramJson);

        if (Objects.isNull(responseRequest)) {
            throw new OmsBaseException(PinDuoDuoConsts.ERROR_CODE_SEND_REQUEST_FAILED, "发送同步接受订单状态消息失败");
        }

        // 取得返回的内容
        Integer returnCode = responseRequest.getErrorCode();
        if (Objects.isNull(returnCode)) {
            throw new OmsBaseException(PinDuoDuoConsts.ERROR_CODE_PARSE_MSG_FAILED, "获取返回消息内容失败");
        }

        if (returnCode == PinDuoDuoConsts.PDD_RETURN_CODE_SUCCESS) {
            saveSyncResult(orderWorkLogChange, OrderStatusConsts.ORDER_STATUS_INPUT, responseRequest);
            return;
        }

        throw new OmsBaseException(PinDuoDuoConsts.ERROR_CODE_SEND_REQUEST_FAILED, "拼多多平台返回失败");
    }

    /**
     * 查询状态同步结果信息
     * @param orderWorkLogChange 
     * @param orderStatus 
     * @return java.lang.Boolean
     * @author wangxiaokun
     */
    private Boolean findSuccessSyncResult(OrderWorkLogChange orderWorkLogChange, int orderStatus) {
        Long orderId = orderWorkLogChange.getOrderId();
        List<OrderNotifyLog> orderNotifyLogs = orderNotifyLogBService.listByOrderId(orderId);
        if (Objects.isNull(orderNotifyLogs)) {
            return Boolean.FALSE;
        }

        for (OrderNotifyLog item : orderNotifyLogs) {
            if (Objects.equals(String.valueOf(orderStatus), item.getNotifyStatus())
                    && Objects.equals(StatusConsts.STATUS_SUCCESS, item.getNotifyResultStatus())) {
                return Boolean.TRUE;
            }
        }

        return Boolean.FALSE;
    }

    /**
     * 处理服务签约请求
     * @param paramsStr 
     * @return void
     * @author wangxiaokun
     */
    protected void parseSignRequest(String paramsStr) throws OmsBaseException {

        // 获取服务签约的具体内容
        PinDuoDuoSignParam pinDuoDuoSignParam = JSONObject.parseObject(paramsStr, PinDuoDuoSignParam.class);

        if (Objects.isNull(pinDuoDuoSignParam)){
            throw new OmsBaseException(PinDuoDuoConsts.ZMN_RETURN_CODE_PARAM_ERROR, "解析服务签约参数失败");
        }
        log.info("【{}】服务签约消息！ 消息:[{}]", PinDuoDuoConsts.CHANNEL_NAME, pinDuoDuoSignParam.toString());

        // 查找店铺是否签约
        PinDuoDuoSignShop pinDuoDuoSignShop = pinDuoDuoSignShopService.findPinDuoDuoSignShopByMallId(pinDuoDuoSignParam.getMallId());
        // 没有签约店铺信息存入数据库
        if (Objects.isNull(pinDuoDuoSignShop)){
            pinDuoDuoSignShop = new PinDuoDuoSignShop();
            pinDuoDuoSignShop.setSignOrderSn(pinDuoDuoSignParam.getSignOrderSn());
            pinDuoDuoSignShop.setMallId(pinDuoDuoSignParam.getMallId());
            pinDuoDuoSignShop.setMallName(pinDuoDuoSignParam.getMallName());
            pinDuoDuoSignShop.setServType(pinDuoDuoSignParam.getServType());
            pinDuoDuoSignShop.setServName(pinDuoDuoSignParam.getServName());
            pinDuoDuoSignShop.setApplyTime(DateUtil.parse(pinDuoDuoSignParam.getApplyTime()));
            if (Objects.nonNull(pinDuoDuoSignParam.getContactInfo())) {
                pinDuoDuoSignShop.setContactName(pinDuoDuoSignParam.getContactInfo().getContactName());
                pinDuoDuoSignShop.setMobile(pinDuoDuoSignParam.getContactInfo().getMobile());
                pinDuoDuoSignShop.setTelephone(pinDuoDuoSignParam.getContactInfo().getTelephone());
            }
            pinDuoDuoSignShop.setAttributes(pinDuoDuoSignParam.getAttributes());
            pinDuoDuoSignShop.setSignShopId(defaultKeyGenerator.generateKey().longValue());
            pinDuoDuoSignShop.setCreater("系统");
            pinDuoDuoSignShop.setUpdater("系统");
            try {
                Integer result = pinDuoDuoSignShopService.addPinDuoDuoSignShop(pinDuoDuoSignShop);
                if (result > 0) {
                    log.info("【{}】保存店铺签约信息成功，保存内容[{}]", PinDuoDuoConsts.CHANNEL_NAME, pinDuoDuoSignShop.toString());
                    // 拼多多店铺消息向厂商服务发一份。
                    /*FactoryMallApplyDIO factoryMallApplyDIO = BeanMapper.map(pinDuoDuoSignShop, FactoryMallApplyDIO.class);
                    factoryMallApplyDIO.setMallName(pinDuoDuoSignShop.getMallName() + "（拼多多）");
                    ResponseDTO responseDTO = factoryApplyModifyRemoteService.addMallApply(factoryMallApplyDIO);
                    if (!responseDTO.isSuccess()){
                        log.info("【{}】向厂商招募推送店铺信息失败！店铺信息:[{}]，Message=[{}]", PinDuoDuoConsts.CHANNEL_NAME,
                                pinDuoDuoSignShop.toString(), responseDTO.getMessage());
                    }*/
                } else {
                    log.info("【{}】保存店铺签约信息失败，保存内容[{}]", PinDuoDuoConsts.CHANNEL_NAME, pinDuoDuoSignShop.toString());
                }
            } catch (RpcException e){
                log.error("【{}】调用厂商招募dubbo失败，error:[{}]", PinDuoDuoConsts.CHANNEL_NAME, e.getMessage());
            } catch (Exception e){
                log.error("【{}】保存店铺签约信息失败，保存内容[{}]，异常[{}]", PinDuoDuoConsts.CHANNEL_NAME, pinDuoDuoSignShop.toString(), e.getMessage());
                throw new OmsBaseException(PinDuoDuoConsts.ZMN_RETURN_CODE_SIGN_SHOP_ERROR, "申请店铺签约失败");
            }
        } else {
            //拼多多签约状态
            Integer status = pinDuoDuoSignShop.getSignStatus();

            // 如果解约或拒绝，重新进入审核状态中
            if (pinDuoDuoSignShop.getSignStatus() == 3 || pinDuoDuoSignShop.getSignStatus() == 2){
                pinDuoDuoSignShop.setSignStatus(0);
                pinDuoDuoSignShop.setSyncStatus(0);
                pinDuoDuoSignShop.setMallName(pinDuoDuoSignParam.getMallName());
                pinDuoDuoSignShop.setServType(pinDuoDuoSignParam.getServType());
                pinDuoDuoSignShop.setServName(pinDuoDuoSignParam.getServName());
                pinDuoDuoSignShop.setApplyTime(DateUtil.parse(pinDuoDuoSignParam.getApplyTime()));
                if (Objects.nonNull(pinDuoDuoSignParam.getContactInfo())) {
                    pinDuoDuoSignShop.setContactName(pinDuoDuoSignParam.getContactInfo().getContactName());
                    pinDuoDuoSignShop.setMobile(pinDuoDuoSignParam.getContactInfo().getMobile());
                    pinDuoDuoSignShop.setTelephone(pinDuoDuoSignParam.getContactInfo().getTelephone());
                }
                pinDuoDuoSignShop.setAttributes(pinDuoDuoSignParam.getAttributes());
            }

            // 修改该店铺签约内容
            pinDuoDuoSignShop.setUpdater("系统");
            pinDuoDuoSignShop.setSignOrderSn(pinDuoDuoSignParam.getSignOrderSn());

            try {
                Integer result = pinDuoDuoSignShopService.modifyPinDuoDuoSignShopByMallId(pinDuoDuoSignShop);
                if (result > 0) {
                    log.info("【{}】修改店铺签约状态成功，修改内容[{}]", PinDuoDuoConsts.CHANNEL_NAME, pinDuoDuoSignShop.toString());
                    // 如果是已解约或拒绝，重新签约，则向厂商招募再推送一次消息
                    if (Objects.equals(status, 3) || Objects.equals(status, 2)){
                        /*FactoryMallApplyDIO factoryMallApplyDIO = BeanMapper.map(pinDuoDuoSignShop, FactoryMallApplyDIO.class);
                        factoryMallApplyDIO.setMallName(pinDuoDuoSignShop.getMallName() + "（拼多多）");
                        ResponseDTO responseDTO = factoryApplyModifyRemoteService.addMallApply(factoryMallApplyDIO);
                        if (!responseDTO.isSuccess()){
                            log.info("【{}】向厂商招募推送店铺信息失败！店铺信息:[{}]，Message=[{}]", PinDuoDuoConsts.CHANNEL_NAME,
                                    pinDuoDuoSignShop.toString(), responseDTO.getMessage());
                        }*/
                    }
                } else {
                    log.info("【{}】修改店铺签约状态失败，修改内容[{}]", PinDuoDuoConsts.CHANNEL_NAME, pinDuoDuoSignShop.toString());
                    throw new OmsBaseException(PinDuoDuoConsts.ZMN_RETURN_CODE_SIGN_SHOP_ERROR, "申请店铺签约失败");
                }
            }catch (Exception e){
                log.error("【{}】修改店铺签约信息失败，修改内容[{}]，异常[{}]", PinDuoDuoConsts.CHANNEL_NAME,
                        pinDuoDuoSignShop.toString(), e.getMessage());
                throw new OmsBaseException(PinDuoDuoConsts.ZMN_RETURN_CODE_SIGN_SHOP_ERROR, "申请店铺签约失败");
            }
            // 如果已签约，直接发送签约结果。
            if (pinDuoDuoSignShop.getSignStatus() == 1){
                PinDuoDuoSendSign pinDuoDuoSendSign = new PinDuoDuoSendSign();
                pinDuoDuoSendSign.setSignOrderSn(pinDuoDuoSignShop.getSignOrderSn());
                pinDuoDuoSendSign.setMallId(pinDuoDuoSignShop.getMallId());
                pinDuoDuoSendSign.setServType(pinDuoDuoSignShop.getServType());
                pinDuoDuoSendSign.setVerifyStatus(PinDuoDuoConsts.PDD_SIGN_ACCEPT);
                String paramJson = JSON.toJSONString(pinDuoDuoSendSign, SerializerFeature.SortField.MapSortField);
                this.sendRequestToPinDuoDuo(PinDuoDuoConsts.PDD_SERVICE_PATH, paramJson);
            }
        }
    }

    /**
     * 根据线索创建订单
     * @param paramsStr
     * @return void
     * @author wangxiaokun
     */
    protected void parseCreateOrderRequest(String paramsStr) throws OmsBaseException {

        // 获取创建订单的具体内容
        PinDuoDuoCreateOrderParam createOrderParam = JSONObject.parseObject(paramsStr, PinDuoDuoCreateOrderParam.class);
        if (Objects.isNull(createOrderParam)){
            throw new OmsBaseException(PinDuoDuoConsts.ZMN_RETURN_CODE_PARAM_ERROR, "解析创建订单参数失败");
        }

        // 查找店铺是否签约
        Long mallId = createOrderParam.getMallId();
        PinDuoDuoSignShop pinDuoDuoSignShop = pinDuoDuoSignShopService.findPinDuoDuoSignShopByMallId(mallId);
        if (Objects.isNull(pinDuoDuoSignShop) || pinDuoDuoSignShop.getSignStatus() != 1){
            throw new OmsBaseException(PinDuoDuoConsts.ZMN_RETURN_CODE_PARAM_ERROR, "参数错误-店铺未申请签约");
        }

        // 生成创建订单的数据
        FactoryNewOrderDTO factoryNewOrderDTO = this.makeZmnCreateOrderData(createOrderParam, pinDuoDuoSignShop);
        if (Objects.isNull(factoryNewOrderDTO)) {
            throw new OmsBaseException(PinDuoDuoConsts.ZMN_RETURN_CODE_REPEAT_ERROR, "重复的订单数据");
        }

        OrderBO orderBO = null;
        try {
            orderBO = factoryOrderBService.insertOrder(factoryNewOrderDTO);
            log.info("【{}】保存订单成功 OrderId:[{}]", PinDuoDuoConsts.CHANNEL_NAME, orderBO.getOrder().getOrderId());
        } catch (OmsBaseException omsBaseException){
            log.error("【{}】保存订单失败 参数:[{}] 消息:[{}]", PinDuoDuoConsts.CHANNEL_NAME, factoryNewOrderDTO.toString(),
                    omsBaseException.getMessage());

            //如果厂商余额不足，统一给拼多多返回余额不足异常
            if (omsBaseException.getMessage().contains("余额不足")){
                throw  new OmsBaseException(PinDuoDuoConsts.ZMN_RETURN_CODE_NOT_BALANCE_ERROR, "余额不足");
            } else {
                throw new OmsBaseException(PinDuoDuoConsts.ZMN_RETURN_CODE_SERVER_ERROR, "创建订单失败");
            }
        } catch (Exception exception) {
            log.error("【{}】保存订单失败 消息:[{}] 异常:[{}]", PinDuoDuoConsts.CHANNEL_NAME, exception.getMessage(),
                    exception);
            throw new OmsBaseException(PinDuoDuoConsts.ZMN_RETURN_CODE_SERVER_ERROR, "创建订单失败");
        }
    }

    /**
     * 预约通知处理
     * @param paramsStr 
     * @return void
     * @author wangxiaokun
     */
    protected void parseAppointNotify(String paramsStr) throws OmsBaseException {

        // 获取预约通知的具体内容
        PinDuoDuoCreateOrderParam createOrderParam = JSONObject.parseObject(paramsStr, PinDuoDuoCreateOrderParam.class);
        if (Objects.isNull(createOrderParam)){
            throw new OmsBaseException(PinDuoDuoConsts.ZMN_RETURN_CODE_PARAM_ERROR, "解析预约通知参数失败");
        }
        log.info("【{}】预约通知消息！消息:[{}]", PinDuoDuoConsts.CHANNEL_NAME, createOrderParam.toString());

        // 工单自动流转
        ZsOrderWorkVO zsOrderWorkVO = zsOrderWorkQueryBService.findOrderWorkByOuterId(createOrderParam.getServOrderSn(),
                null);
        if (Objects.nonNull(zsOrderWorkVO)) {

            //将预约通知添加到操作日志“用户已签收”
            OrderLog orderLog = new OrderLog();
            orderLog.setOrderId(zsOrderWorkVO.getOrderId());
            orderLog.setWorkId(zsOrderWorkVO.getWorkId());
            orderLog.setType(OrderLogConsts.ORDER_LOG_TYPE_CHANNEL_REMARK);
            orderLog.setTypeName(OrderLogConsts.getOrderLogTypeName(OrderLogConsts.ORDER_LOG_TYPE_CHANNEL_REMARK));
            orderLog.setBeforeStatus(zsOrderWorkVO.getStatus());
            orderLog.setBeforeStatusName(OrderStatusConsts.getWorkStatusName(zsOrderWorkVO.getStatus()));
            orderLog.setBeforeResultStatus(zsOrderWorkVO.getResultStatus());
            orderLog.setBeforeResultStatusName(OrderStatusConsts.getWorkResultStatusName(
                    zsOrderWorkVO.getResultStatus()));
            orderLog.setAfterStatus(zsOrderWorkVO.getStatus());
            orderLog.setAfterStatusName(OrderStatusConsts.getWorkStatusName(zsOrderWorkVO.getStatus()));
            orderLog.setAfterResultStatus(zsOrderWorkVO.getResultStatus());
            orderLog.setAfterResultStatusName(OrderStatusConsts.getWorkResultStatusName(
                    zsOrderWorkVO.getResultStatus()));
            orderLog.setOperator("渠道");
            orderLog.setOperatorId((long) zsOrderWorkVO.getChannelId());
            orderLog.setOperatorType(GlobalConsts.OPERATE_USER_TYPE_CHANNEL);
            orderLog.setContent("用户已签收");
            orderLogBService.save(orderLog);

            //工单自动流转
            workFlowContextBService.asyncAutoFlow(zsOrderWorkVO.getOrderId(), zsOrderWorkVO.getWorkId());

            //如果预约通知时有预约时间，再同步一次预约时间。
            if (Objects.nonNull(zsOrderWorkVO.getDutyTime())){
                OrderWorkLogChange orderWorkLogChange = new OrderWorkLogChange();
                orderWorkLogChange.setOuterId(zsOrderWorkVO.getOuterId());
                orderWorkLogChange.setDutyTime(zsOrderWorkVO.getDutyTime());
                orderWorkLogChange.setOrderId(zsOrderWorkVO.getOrderId());
                orderWorkLogChange.setWorkId(zsOrderWorkVO.getWorkId());
                orderWorkLogChange.setChannelId(zsOrderWorkVO.getChannelId());
                orderWorkLogChange.setStatus(zsOrderWorkVO.getStatus());
                orderWorkLogChange.setResultStatus(zsOrderWorkVO.getResultStatus());
                try {
                    this.sendAppointOrderToPinDuoDuo(orderWorkLogChange);
                } catch (OmsBaseException omsBaseException) {
                    log.error("【{}】收到预约通知消息，同步预约时间失败！工单号：[{}]", PinDuoDuoConsts.CHANNEL_NAME,
                            zsOrderWorkVO.getWorkId());
                }
            }

            // 自动跟单
            this.autoOrderTrack(zsOrderWorkVO);
        }else {
            log.info("【{}-API】 没找到线索，线索id为:[{}]", PinDuoDuoConsts.CHANNEL_NAME, createOrderParam.getServOrderSn());
            throw new OmsBaseException(PinDuoDuoConsts.ZMN_RETURN_CODE_PARAM_ERROR,
                    String.format("预约通知找不到对应的订单 拼多多服务单号:servOrderSn=[%s]", createOrderParam.getServOrderSn()));
        }
    }

    /**
     * 用户已签收发起自动跟单
     *
     * @param zsOrderWorkVO
     */
    private void autoOrderTrack(ZsOrderWorkVO zsOrderWorkVO) {

        //查询是否存在用户签收跟单 && 跟单未完成
        OrderTrackQuery query = new OrderTrackQuery();
        query.setOrderId(zsOrderWorkVO.getOrderId());
        query.setWorkId(zsOrderWorkVO.getWorkId());
        query.setMapId(OrderConsts.ORDER_TRACT_PDD_TYPE_ID);
        query.setComplete(GlobalConsts.NO);
        Integer orderTrackCount = orderTrackBService.countByQuery(query);
        log.info("#api#orderTrackCount 查询跟单是否完成：【{}】", JSON.toJSONString(orderTrackCount));
        // 有进行中的跟单则不创建跟单
        if (orderTrackCount != null && orderTrackCount > 0) {
            return;
        }

        //查询指定的跟单信息
        /*List<OrderTrackVO> trackTypeList = Lists.newArrayList();
        DocumentaryContentDIO documentaryContentDIO = new DocumentaryContentDIO();
        documentaryContentDIO.setBizType(zsOrderWorkVO.getBizType());
        documentaryContentDIO.setStatus(GlobalConsts.YES);
        documentaryContentDIO.setId(OrderConsts.ORDER_TRACT_PDD_TYPE_ID);
        log.info("#api#track 查询跟单项目入参：【{}】", JSON.toJSONString(documentaryContentDIO));
        ResponseDTO<List<DocumentaryContentDRO>> responseDTO = documentaryContentListRemoteService.listByQuery(documentaryContentDIO);
        log.info("#api#track 查询跟单项目出参：【{}】", JSON.toJSONString(responseDTO));

        if (!responseDTO.isSuccess() || CollectionUtils.isEmpty(responseDTO.getData())) {
            log.info("#api#trackTypeList 查询跟单项失败或为空，不处理--------");
            return;
        }

        responseDTO.getData().forEach(e -> {
            // 默认跟单等级为一级
            OrderTrackVO orderTrackVO = OrderTrackVO.builder().mapId(e.getId()).mapName(e.getContent()).level(OrderConsts.ORDER_TRACT_OTHER_TYPE_LEVEL).build();
            trackTypeList.add(orderTrackVO);
        });

        // 保存跟单信息
        OrderTrackDTO orderTrackDTO = new OrderTrackDTO();
        orderTrackDTO.setComplete(GlobalConsts.NO);
        orderTrackDTO.setOrderId(zsOrderWorkVO.getOrderId());
        orderTrackDTO.setWorkId(zsOrderWorkVO.getWorkId());
        orderTrackDTO.setOperator("系统");
        orderTrackDTO.setOperatorId((long) zsOrderWorkVO.getChannelId());
        orderTrackDTO.setOperatorType(GlobalConsts.OPERATE_USER_TYPE_CHANNEL);

        List<OrderTrackDetailDTO> detailDTOList = new ArrayList<>(trackTypeList.size());
        orderTrackDTO.setDetailDTOList(detailDTOList);

        trackTypeList.forEach(workTrackDTO -> {

            // 添加到跟单列表
            OrderTrackDetailDTO orderTrackDetailDTO = new OrderTrackDetailDTO();
            orderTrackDetailDTO.setMapId(workTrackDTO.getMapId());
            orderTrackDetailDTO.setMapName(workTrackDTO.getMapName());
            orderTrackDetailDTO.setRemark(workTrackDTO.getRemark());
            orderTrackDetailDTO.setLevel(workTrackDTO.getLevel());
            detailDTOList.add(orderTrackDetailDTO);
        });

        // 保存
        orderTrackBService.updateTrack(orderTrackDTO);*/
    }

    /**
     * 转换拼多多的创建订单为啄木鸟平台的创建订单数据对象
     * @param createOrderParam 
     * @return com.zmn.oms.model.dto.order.zmn.FactoryNewOrderDTO
     * @author wangxiaokun
     */
    protected FactoryNewOrderDTO makeZmnCreateOrderData(PinDuoDuoCreateOrderParam createOrderParam,
                                                        PinDuoDuoSignShop pinDuoDuoSignShop) throws OmsBaseException {

        // 获取服务单号
        String servOrderSn = createOrderParam.getServOrderSn();

        // 判断订单是否重复
        ZsOrderWorkVO zsOrderWorkVO = zsOrderWorkQueryBService.findOrderWorkByOuterId(servOrderSn, null);
        if (Objects.nonNull(zsOrderWorkVO)) {
            log.info("【{}-API】 重复的线索，线索id为:[{}]", PinDuoDuoConsts.CHANNEL_NAME, servOrderSn);
            return null;
        }

        FactoryNewOrderDTO factoryNewOrderDTO = new FactoryNewOrderDTO();

        // 渠道订单id
        factoryNewOrderDTO.setOuterId(servOrderSn);

        // 预约时间
        factoryNewOrderDTO.setDutyTime(null);

        // 联系人
        factoryNewOrderDTO.setUserName(createOrderParam.getContactInfo().getContactName());

        // 性别
        factoryNewOrderDTO.setGender(GlobalDict.GENDER_NO);

        // 电话
        factoryNewOrderDTO.setTelephone(createOrderParam.getContactInfo().getMobile());

        // 电话2
        factoryNewOrderDTO.setTelephone2(createOrderParam.getContactInfo().getTelephone());

        // 地址
        factoryNewOrderDTO.setAddress(createOrderParam.getContactInfo().getAddrDetail());

        // 街道
        factoryNewOrderDTO.setStreet("");

        // 类型
        factoryNewOrderDTO.setType(OrderConsts.ORDER_TYPE_NEW);

        // 录入类型
        factoryNewOrderDTO.setInputType(OrderConsts.ORDER_INPUT_TYPE_API);

        // 操作者
        factoryNewOrderDTO.setOperator("系统");

        // 操作者类型
        factoryNewOrderDTO.setOperatorType(GlobalConsts.OPERATE_USER_TYPE_CHANNEL);

        // 备注
        factoryNewOrderDTO.setRemark(Optional.ofNullable(createOrderParam.getRemark()).orElse(""));

        // 平台标志
        factoryNewOrderDTO.setPlat(GlobalConsts.PLAT_MARK_YEYX);

        // 下单入口
        factoryNewOrderDTO.setReceiveEntranceId(GateTypeConsts.GATE_API_TMALL);

        // 保内
        factoryNewOrderDTO.setBizType(com.zmn.consts.GlobalConsts.BIZ_TYPE_F);

        // 下单方式
        factoryNewOrderDTO.setReceiverManner(OrderConsts.RECEIVE_MANNER_API);

        // 厂商信息
        OrderFactoryDTO orderFactory = new OrderFactoryDTO();
        // 厂商id
        orderFactory.setFactoryId(pinDuoDuoSignShop.getFactoryId());

        // 产品id
        ResponseDTO<List<ProductBaseDRO>> servProductListResponseDTO = channelProductThirdListRemoteService.listByChannelIdAndProductParentIdAndSubId(PinDuoDuoConsts.PDD_CHANNEL_ID,
                String.valueOf(createOrderParam.getCategoryId()), null);
        log.info("【{}】 #ChannelProductMapListRemoteService#listByChannelIdAndProductParentIdAndProductSubId# 入参【{}】【{}】，出参【{}】",
                PinDuoDuoConsts.CHANNEL_NAME, PinDuoDuoConsts.PDD_CHANNEL_ID, createOrderParam.getCategoryId(),
                servProductListResponseDTO.toString());
        if (!servProductListResponseDTO.isSuccess() || Objects.isNull(servProductListResponseDTO.getData()) ||
                servProductListResponseDTO.getData().isEmpty()) {
            orderFactory.setProductId(PinDuoDuoMapper.getProductId(createOrderParam.getCategoryId()));
        } else {
            orderFactory.setProductId(servProductListResponseDTO.getData().get(0).getProductId());
        }

        // 产品数量
        orderFactory.setFcProductNumber(createOrderParam.getGoodsNum());
        factoryNewOrderDTO.setOrderFactory(orderFactory);

        // 操作者id
        factoryNewOrderDTO.setOperatorId((long)pinDuoDuoSignShop.getChannelId());

        // 城市id
        String areaName = createOrderParam.getContactInfo().getProvName() + createOrderParam.getContactInfo().getCityName()
                + createOrderParam.getContactInfo().getDistrictName() + createOrderParam.getContactInfo().getAddrDetail();
        log.info("【{}】创建订单的详细地址信息:[{}]", PinDuoDuoConsts.CHANNEL_NAME, areaName);

        String operatorLogRemark = String.format("拼多多服务单号：%s，快递单号：%s，模版报价：%s元（此价格仅供参考，非最终成交" +
                "价格），下单时间：%s，服务单类型：%s，商家id：%s，商品类目名称：%s，商品名称：%s，Sku名称：%s，客户地址：%s",
                createOrderParam.getServOrderSn(), createOrderParam.getMailNo(),
                MoneyUtil.parseToYuan(createOrderParam.getTplPrice()), createOrderParam.getOrderCreateTime(),
                createOrderParam.getServType(), createOrderParam.getMallId(), createOrderParam.getCategoryName(),
                createOrderParam.getGoodsName(), createOrderParam.getSkuName(), areaName);

        //灯的扩展信息
        LampAttribute attribute = JSONObject.parseObject(createOrderParam.getAttributes(), LampAttribute.class);
        if (Objects.nonNull(attribute)){
            operatorLogRemark = String.format("%s，扩展信息-商品属性信息：{灯具形状：%s，灯罩材质：%s，吊灯类型：%s，高度：%s，" +
                    "长度：%s，灯头数：%s，灯盏数：%s，图片：<ul class=\"container-images\" id=\"skuImg\"><li>" +
                    "<img src=\"%s\" ></li></ul>}", operatorLogRemark, attribute.getShape(), attribute.getMaterial(),
                    attribute.getChandelierType(), attribute.getHeight(), attribute.getLength(),
                    attribute.getLampHolderNum(), attribute.getLampCalyxNum(), attribute.getSkuImg());
        }

        // 城市id , 默认重庆
        Integer cityId = 500100;
        do {
            if (StringUtil.isNullOrEmpty(areaName)) {
                break;
            }

            // 查找经纬度
            LngLatLocation areaLocation = baiduMapBService.location(areaName);
            if (Objects.isNull(areaLocation)) {
                break;
            }

            // 经纬度查找区域信息
            ResponseDTO<AreaDRO> areaResponse = areaListRemoteService.getAreaByLatAndLng(Double.valueOf(areaLocation.getLng()), Double.valueOf(areaLocation.getLat()));
            if (Objects.isNull(areaResponse) || Objects.isNull(areaResponse.getData())) {
                break;
            }

            cityId = Integer.valueOf(areaResponse.getData().getParentId());

            Double longitude = Double.valueOf(areaResponse.getData().getLongitude());
            Double latitude = Double.valueOf(areaResponse.getData().getLatitude());

            // 设置经纬度
            factoryNewOrderDTO.setLongitude(longitude);
            factoryNewOrderDTO.setLatitude(latitude);

            operatorLogRemark = String.format("%s，经纬度：%s, %s", operatorLogRemark, longitude, latitude);
        } while (false);

        // 设置城市id
        factoryNewOrderDTO.setCityId(cityId);

        // 操作日志
        factoryNewOrderDTO.setOperatorLogRemark(operatorLogRemark);

        // 预约时间
        factoryNewOrderDTO.setDutyTime(null);

        log.info("【{}-API】 创建的的订单信息:[{}]", PinDuoDuoConsts.CHANNEL_NAME, factoryNewOrderDTO.toString());
        return factoryNewOrderDTO;
    }

    /**
     * 发送消息给拼多多服务
     * @param pathRequest 
     * @param paramJson 
     * @return com.zmn.oms.third.pinduoduo.dto.api.PinDuoDuoResponse
     * @author wangxiaokun
     */
    @Override
    public PinDuoDuoResponse sendRequestToPinDuoDuo(String pathRequest, String paramJson) {

        // 判断参数是否正确
        if (Objects.isNull(pathRequest) || pathRequest.isEmpty() || Objects.isNull(paramJson) || paramJson.isEmpty()) {
            return null;
        }

        PinDuoDuoSendRequest pinDuoDuoSendRequest = new PinDuoDuoSendRequest();

        // 判断是否核销码
        if (paramJson.contains("verifyCode")){
            pinDuoDuoSendRequest.setType(PinDuoDuoConsts.PDD_SERVICE_AFTERSALES_VERIFY_CHECK_FALG);
        }

        // 判断是否签约结果回传
        if (paramJson.contains("verifyStatus")){
            pinDuoDuoSendRequest.setType(PinDuoDuoConsts.PDD_SERVICE_AFTERSALES_SIGN_NOTIFY_FLAG);
        }

        // 判断是否服务实操回告
        if (paramJson.contains("bizStatus")){
            pinDuoDuoSendRequest.setType(PinDuoDuoConsts.PDD_SERVICE_AFTERSALES_BIZACTION_NOTYFY_FALG);
        }

        pinDuoDuoSendRequest.setClient_id(PinDuoDuoConsts.PDD_CLIENT_ID);
        pinDuoDuoSendRequest.setTimestamp(DateUtil.getNowTimestamp());
        pinDuoDuoSendRequest.setPartner_id(PinDuoDuoConsts.PDD_PARTNER_ID);
        pinDuoDuoSendRequest.setTarget_client_id(PinDuoDuoConsts.PDD_TARGET_CLIENT_ID);
        pinDuoDuoSendRequest.setRequest_id("zmn_pdd_" + DateUtil.getNowTimestamp());
        pinDuoDuoSendRequest.setRequest(paramJson);

        // 发送请求
        PinDuoDuoResponse responseRequest = this.sendRequestToPinDuoDuo(pathRequest, pinDuoDuoSendRequest);
        if (Objects.isNull(responseRequest)) {
            log.info("【{}-API】 发送请求失败", PinDuoDuoConsts.CHANNEL_NAME);
            return null;
        }

        return responseRequest;
    }

    /**
     * 同步服务预约给拼多多服务
     * @param orderWorkLogChange 
     * @return void
     * @author wangxiaokun
     */
    @Override
    public void sendAppointOrderToPinDuoDuo(OrderWorkLogChange orderWorkLogChange) throws OmsBaseException{
        // 参数判断
        if (Objects.isNull(orderWorkLogChange)) {
            throw new OmsBaseException(PinDuoDuoConsts.ERROR_CODE_PARAM_INVALID, "消息通知参数为空");
        }

        //判断是否设置预约时间操作
        Date dutyTime = orderWorkLogChange.getDutyTime();
        if (Objects.isNull(dutyTime)){
            return;
        }

        String outerId = orderWorkLogChange.getOuterId();
        // 判断外部工单id
        if (Objects.isNull(outerId) || outerId.isEmpty()) {
            throw new OmsBaseException(PinDuoDuoConsts.ERROR_CODE_SERVER_UNKNOWN, "消息通知参数错误-没有对应的外部订单Id");
        }

        PinDuoDuoAcceptOrderDTO pinDuoDuoAcceptOrderDTO = new PinDuoDuoAcceptOrderDTO();
        pinDuoDuoAcceptOrderDTO.setServOrderSn(outerId);
        pinDuoDuoAcceptOrderDTO.setBizStatus(PinDuoDuoConsts.PDD_APPOINT_SERV);
        pinDuoDuoAcceptOrderDTO.setAppointServTime(DateUtil.toString(orderWorkLogChange.getDutyTime(), "yyyy-MM-dd HH:mm:ss"));
        pinDuoDuoAcceptOrderDTO.setAppointServEndTime(DateUtil.toString(orderWorkLogChange.getDutyTime(), "yyyy-MM-dd HH:mm:ss"));
        pinDuoDuoAcceptOrderDTO.setExecuteTime(DateUtil.toString(DateUtil.getNow(), "yyyy-MM-dd HH:mm:ss"));
        log.info("【{}-API】 预约通知，预约时间:[{}]", PinDuoDuoConsts.CHANNEL_NAME, DateUtil.toString(orderWorkLogChange.getDutyTime(), "yyyy-MM-dd HH:mm:ss"));

        // 是否改约
        OrderChangeRecord orderChangeRecord = orderChangeRecordService.getChangeRecordByOrderId(orderWorkLogChange.getOrderId());
        if (Objects.nonNull(orderChangeRecord)) {
            log.info("【{}-API】 预约通知，消息:[{}]", PinDuoDuoConsts.CHANNEL_NAME, orderChangeRecord.toString());
            if (orderChangeRecord.getDutyTimeModifyCount() > 0) {
                pinDuoDuoAcceptOrderDTO.setBizStatus(PinDuoDuoConsts.PDD_CHANGE_APPOINT);
                pinDuoDuoAcceptOrderDTO.setAppointServTime(DateUtil.toString(orderChangeRecord.getLastDutyTime(), "yyyy-MM-dd HH:mm:ss"));
                pinDuoDuoAcceptOrderDTO.setAppointServEndTime(DateUtil.toString(orderChangeRecord.getLastDutyTime(), "yyyy-MM-dd HH:mm:ss"));
            }
        }

        // 发送http请求
        String paramJson = JSON.toJSONString(pinDuoDuoAcceptOrderDTO, SerializerFeature.SortField.MapSortField);
        PinDuoDuoResponse responseRequest = sendRequestToPinDuoDuo(PinDuoDuoConsts.PDD_SERVICE_PATH, paramJson);
        if (Objects.isNull(responseRequest) || responseRequest.getErrorCode() != PinDuoDuoConsts.PDD_RETURN_CODE_SUCCESS) {
            throw new OmsBaseException(PinDuoDuoConsts.ERROR_CODE_SEND_REQUEST_FAILED, "同步服务预约消息失败");
        }

        this.saveSyncResult(orderWorkLogChange, OrderStatusConsts.ORDER_STATUS_CONFIRM, responseRequest);
    }

    /**
     * 同步派单给拼多多服务
     * @param orderWorkLogChange 
     * @return void
     * @author wangxiaokun
     */
    @Override
    public void sendUpdateOrderToPinDuoDuo(OrderWorkLogChange orderWorkLogChange) throws OmsBaseException {

        // 参数判断
        if (Objects.isNull(orderWorkLogChange)) {
            throw new OmsBaseException(PinDuoDuoConsts.ERROR_CODE_PARAM_INVALID, "消息通知参数为空");
        }

        // 获取工单信息
        OrderWork orderWork = orderWorkService.findOrderWorkByKey(orderWorkLogChange.getOrderId(), orderWorkLogChange.getWorkId());
        if (Objects.isNull(orderWork)) {
            throw new OmsBaseException(PinDuoDuoConsts.ERROR_CODE_SERVER_UNKNOWN, "查不到对应的工单信息");
        }

        String outerId = orderWorkLogChange.getOuterId();
        // 判断外部工单id
        if (Objects.isNull(outerId) || outerId.isEmpty()) {
            throw new OmsBaseException(PinDuoDuoConsts.ERROR_CODE_SERVER_UNKNOWN, "消息通知参数错误-没有对应的外部订单Id");
        }

        PinDuoDuoAcceptOrderDTO pinDuoDuoAcceptOrderDTO = new PinDuoDuoAcceptOrderDTO();
        pinDuoDuoAcceptOrderDTO.setServOrderSn(outerId);
        pinDuoDuoAcceptOrderDTO.setBizStatus(PinDuoDuoConsts.PDD_ALLOCK_WORKER);
        pinDuoDuoAcceptOrderDTO.setExecuteTime(DateUtil.toString(orderWork.getDistributeTime(), "yyyy-MM-dd HH:mm:ss"));
        pinDuoDuoAcceptOrderDTO.setAttributes(String.format(
                "{\"staffName\":\"%s\",\"staffPhone\":\"%s\"}",
                Optional.ofNullable(orderWork.getMasterName())
                        .filter(name -> name.length() >= 1)
                        .map(name -> String.format("%s工程师", name.substring(0,1)))
                        .orElse("工程师"),
                Optional.ofNullable(orderDetailService.findOrderDetailByKey(orderWork.getOrderId()))
                        .map(orderDetail -> {
                            if (Objects.equals(orderDetail.getBindStatus(), OrderConsts.BIND_STATUS_BIND)
                                    && org.apache.commons.lang3.StringUtils.isNotBlank(orderDetail.getBindTelephone())) {
                                return orderDetail.getBindTelephone();
                            }
                            return null;
                        })
                        .orElse(MasterPhoneUtil.getSafeMasterPhone(orderWork.getCityId()))
        ));

        // 发送http请求
        String paramJson = JSON.toJSONString(pinDuoDuoAcceptOrderDTO, SerializerFeature.SortField.MapSortField);
        PinDuoDuoResponse responseRequest = sendRequestToPinDuoDuo(PinDuoDuoConsts.PDD_SERVICE_PATH, paramJson);
        if (Objects.isNull(responseRequest) || responseRequest.getErrorCode() != PinDuoDuoConsts.PDD_RETURN_CODE_SUCCESS) {
            throw new OmsBaseException(PinDuoDuoConsts.ERROR_CODE_SEND_REQUEST_FAILED, "同步派单消息失败");
        }

        this.saveSyncResult(orderWorkLogChange, OrderStatusConsts.ORDER_STATUS_DISTRIBUTE, responseRequest);
    }

    /**
     * 同步工程师上门给拼多多服务
     * @param orderWorkLogChange 
     * @return void
     * @author wangxiaokun
     */
    @Override
    public void sendBeginServiceToPinDuoDuo(OrderWorkLogChange orderWorkLogChange) throws OmsBaseException {

        // 参数判断
        if (Objects.isNull(orderWorkLogChange)) {
            throw new OmsBaseException(PinDuoDuoConsts.ERROR_CODE_PARAM_INVALID, "消息通知参数为空");
        }

        // 获取工单信息
        OrderWork orderWork = orderWorkService.findOrderWorkByKey(orderWorkLogChange.getOrderId(), orderWorkLogChange.getWorkId());
        if (Objects.isNull(orderWork)) {
            throw new OmsBaseException(PinDuoDuoConsts.ERROR_CODE_SERVER_UNKNOWN, "查不到对应的工单信息");
        }

        String outerId = orderWorkLogChange.getOuterId();
        // 判断外部工单id
        if (Objects.isNull(outerId) || outerId.isEmpty()) {
            throw new OmsBaseException(PinDuoDuoConsts.ERROR_CODE_SERVER_UNKNOWN, "消息通知参数错误-没有对应的外部订单Id");
        }

        PinDuoDuoAcceptOrderDTO pinDuoDuoAcceptOrderDTO = new PinDuoDuoAcceptOrderDTO();
        pinDuoDuoAcceptOrderDTO.setServOrderSn(outerId);
        pinDuoDuoAcceptOrderDTO.setBizStatus(PinDuoDuoConsts.PDD_SIGN_SERV);
        pinDuoDuoAcceptOrderDTO.setExecuteTime(DateUtil.toString(orderWork.getVisitTime(), "yyyy-MM-dd HH:mm:ss"));

        // 发送http请求
        String paramJson = JSON.toJSONString(pinDuoDuoAcceptOrderDTO, SerializerFeature.SortField.MapSortField);
        PinDuoDuoResponse responseRequest = sendRequestToPinDuoDuo(PinDuoDuoConsts.PDD_SERVICE_PATH, paramJson);
        if (Objects.isNull(responseRequest) || responseRequest.getErrorCode() != PinDuoDuoConsts.PDD_RETURN_CODE_SUCCESS) {
            throw new OmsBaseException(PinDuoDuoConsts.ERROR_CODE_SEND_REQUEST_FAILED, "同步工程师上门消息失败");
        }

        this.saveSyncResult(orderWorkLogChange, OrderStatusConsts.ORDER_STATUS_VISIT, responseRequest);
    }

    /**
     * 同步取消订单给拼多多服务
     * @param orderWorkLogChange 
     * @return void
     * @author wangxiaokun
     */
    @Override
    public void sendCancelOrderToPinDuoDuo(OrderWorkLogChange orderWorkLogChange) throws OmsBaseException {

        // 参数判断
        if (Objects.isNull(orderWorkLogChange)) {
            throw new OmsBaseException(PinDuoDuoConsts.ERROR_CODE_PARAM_INVALID, "消息通知参数为空");
        }

        // 获取工单信息
        OrderWork orderWork = orderWorkService.findOrderWorkByKey(orderWorkLogChange.getOrderId(), orderWorkLogChange.getWorkId());
        if (Objects.isNull(orderWork)) {
            throw new OmsBaseException(PinDuoDuoConsts.ERROR_CODE_SERVER_UNKNOWN, "查不到对应的工单信息");
        }

        String outerId = orderWorkLogChange.getOuterId();
        // 判断外部工单id
        if (Objects.isNull(outerId) || outerId.isEmpty()) {
            throw new OmsBaseException(PinDuoDuoConsts.ERROR_CODE_SERVER_UNKNOWN, "消息通知参数错误-没有对应的外部订单Id");
        }

        // 取消备注（原因），需要将手写备注和选项备注进行拼接
        OrderRemarkVO orderRemarkVO = orderRemarkBService.findOrderRemarkVO(orderWorkLogChange.getOrderId(), orderWorkLogChange.getWorkId(),
                OrderConsts.ORDER_REMARK_TYPE_CANCEL);
        List<String> remarkList = new LinkedList<>();
        if (StringUtils.isNotBlank(orderRemarkVO.getContent())) {
            remarkList.add(orderRemarkVO.getContent());
        }
        if (orderRemarkVO.getDetailVOList() != null) {
            for (OrderRemarkDetailVO item : orderRemarkVO.getDetailVOList()) {
                remarkList.add(item.getMapName());
            }
        }
        String remark = (remarkList.size() > 0) ? StringUtils.join(remarkList, "，") : null;

        PinDuoDuoAcceptOrderDTO pinDuoDuoAcceptOrderDTO = new PinDuoDuoAcceptOrderDTO();
        pinDuoDuoAcceptOrderDTO.setServOrderSn(outerId);
        pinDuoDuoAcceptOrderDTO.setBizStatus(PinDuoDuoConsts.PDD_CHARGE_BACK);
        pinDuoDuoAcceptOrderDTO.setBizDetailDesc(remark);
        pinDuoDuoAcceptOrderDTO.setExecuteTime(DateUtil.toString(orderWork.getCancelTime(), "yyyy-MM-dd HH:mm:ss"));

        // 发送http请求
        String paramJson = JSON.toJSONString(pinDuoDuoAcceptOrderDTO, SerializerFeature.SortField.MapSortField);
        PinDuoDuoResponse responseRequest = sendRequestToPinDuoDuo(PinDuoDuoConsts.PDD_SERVICE_PATH, paramJson);
        if (Objects.isNull(responseRequest) || responseRequest.getErrorCode() != PinDuoDuoConsts.PDD_RETURN_CODE_SUCCESS) {
            throw new OmsBaseException(PinDuoDuoConsts.ERROR_CODE_SEND_REQUEST_FAILED, "同步取消订单消息失败");
        }

        this.saveSyncResult(orderWorkLogChange, OrderStatusConsts.ORDER_STATUS_CANCEL, responseRequest);
    }

    /**
     * 同步订单完成给拼多多服务
     * @param orderWorkLogChange 
     * @return void
     * @author wangxiaokun
     */
    @Override
    public void sendFinishOrderToPinDuoDuo(OrderWorkLogChange orderWorkLogChange) throws OmsBaseException {
        // 参数判断
        if (Objects.isNull(orderWorkLogChange)) {
            throw new OmsBaseException(PinDuoDuoConsts.ERROR_CODE_PARAM_INVALID, "消息通知参数为空");
        }

        // 获取工单信息
        OrderWork orderWork = orderWorkService.findOrderWorkByKey(orderWorkLogChange.getOrderId(), orderWorkLogChange.getWorkId());
        if (Objects.isNull(orderWork)) {
            throw new OmsBaseException(PinDuoDuoConsts.ERROR_CODE_SERVER_UNKNOWN, "查不到对应的工单信息");
        }

        String outerId = orderWorkLogChange.getOuterId();
        // 判断外部工单id
        if (Objects.isNull(outerId) || outerId.isEmpty()) {
            throw new OmsBaseException(PinDuoDuoConsts.ERROR_CODE_SERVER_UNKNOWN, "消息通知参数错误-没有对应的外部订单Id");
        }

        PinDuoDuoAcceptOrderDTO pinDuoDuoAcceptOrderDTO = new PinDuoDuoAcceptOrderDTO();
        pinDuoDuoAcceptOrderDTO.setServOrderSn(outerId);
        pinDuoDuoAcceptOrderDTO.setBizStatus(PinDuoDuoConsts.PDD_DONE_SERV);
        pinDuoDuoAcceptOrderDTO.setCheckPrice(orderWork.getMasterAmount());
        pinDuoDuoAcceptOrderDTO.setExecuteTime(DateUtil.toString(Optional.ofNullable(orderWork.getServiceCompleteTime()).orElse(DateUtil.getNow()), "yyyy-MM-dd HH:mm:ss"));

        // 发送http请求
        String paramJson = JSON.toJSONString(pinDuoDuoAcceptOrderDTO, SerializerFeature.SortField.MapSortField);
        PinDuoDuoResponse responseRequest = sendRequestToPinDuoDuo(PinDuoDuoConsts.PDD_SERVICE_PATH, paramJson);
        if (Objects.isNull(responseRequest) || responseRequest.getErrorCode() != PinDuoDuoConsts.PDD_RETURN_CODE_SUCCESS) {
            throw new OmsBaseException(PinDuoDuoConsts.ERROR_CODE_SEND_REQUEST_FAILED, "同步订单完成消息失败");
        }

        this.saveSyncResult(orderWorkLogChange, OrderStatusConsts.ORDER_STATUS_COMPLETE, responseRequest);
    }

    /**
     * 同步核销码给拼多多服务
     * @param orderId
     * @param wordId
     * @param code
     * @return void
     * @author wangxiaokun
     */
    @Override
    public void sendVerifyCheckToPinDuoDuo(Long orderId, Long wordId, String code, Integer channelId) throws OmsBaseException{

        if (Objects.isNull(code)){
            throw new OmsBaseException(PinDuoDuoConsts.ERROR_CODE_PARAM_INVALID, "完成码为空");
        }

        // 参数判断
        if (Objects.isNull(orderId)) {
            throw new OmsBaseException(PinDuoDuoConsts.ERROR_CODE_PARAM_INVALID, "订单参数为空");
        }

        // 获取工单信息
        OrderWork orderWork = orderWorkService.findOrderWorkByKey(orderId, wordId);
        if (Objects.isNull(orderWork)) {
            throw new OmsBaseException(PinDuoDuoConsts.ERROR_CODE_SERVER_UNKNOWN, "查不到对应的工单信息");
        }

        String outerId = orderWork.getOuterId();
        // 判断外部工单id
        if (Objects.isNull(outerId) || outerId.isEmpty()) {
            throw new OmsBaseException(PinDuoDuoConsts.ERROR_CODE_SERVER_UNKNOWN, "消息通知参数错误-没有对应的外部订单Id");
        }

        PinDuoDuoAcceptOrderDTO pinDuoDuoAcceptOrderDTO = new PinDuoDuoAcceptOrderDTO();
        pinDuoDuoAcceptOrderDTO.setServOrderSn(outerId);
        pinDuoDuoAcceptOrderDTO.setVerifyCode(code);
        pinDuoDuoAcceptOrderDTO.setExecuteTime(DateUtil.toString(DateUtil.getNow(), "yyyy-MM-dd HH:mm:ss"));

        // 发送http请求
        String paramJson = JSON.toJSONString(pinDuoDuoAcceptOrderDTO, SerializerFeature.SortField.MapSortField);
        PinDuoDuoResponse responseRequest = sendRequestToPinDuoDuo(PinDuoDuoConsts.PDD_SERVICE_PATH, paramJson);
        if (Objects.isNull(responseRequest) || responseRequest.getErrorCode() != PinDuoDuoConsts.PDD_RETURN_CODE_SUCCESS) {
            throw new OmsBaseException(PinDuoDuoConsts.ERROR_CODE_SEND_REQUEST_FAILED, "同步完成码消息失败");
        }

        // 保存通知日志
        OrderNotifyLog orderNotifyLog = new OrderNotifyLog();
        orderNotifyLog.setOrderId(orderId);
        orderNotifyLog.setChannelId(channelId);
        orderNotifyLog.setOrderStatus(61);
        orderNotifyLog.setOrderResultStatus(2);
        orderNotifyLog.setNotifyStatus(String.valueOf(OrderStatusConsts.ORDER_STATUS_COMPLETE));
        orderNotifyLog.setType(OrderConsts.ORDER_NOTIFY_TYPE_CHANGE);
        orderNotifyLog.setNotifyTime(DateUtil.getNow());
        orderNotifyLog.setNotifyResultMsg(String.format("[%s]-%s",
                OrderStatusConsts.getOrderStatusName(OrderStatusConsts.ORDER_STATUS_COMPLETE), responseRequest.getErrorMsg()));
        ResultDTO resultDTO = new ResultDTO();
        resultDTO.setStatus(responseRequest.getErrorCode() == PinDuoDuoConsts.PDD_RETURN_CODE_SUCCESS ? StatusConsts.STATUS_SUCCESS : StatusConsts.STATUS_ERROR);
        resultDTO.setData(orderNotifyLog);

        orderNotifyLogBService.saveNotifyLog(resultDTO);
    }

    /**
     * 厂商管理店铺审核结果处理
     * @param pinDuoDuoShopExamineDTO
     * @return void
     * @author wangxiaokun
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void examineResult(PinDuoDuoShopExamineDTO pinDuoDuoShopExamineDTO) {

        //判断参数是否为空
        if (Objects.isNull(pinDuoDuoShopExamineDTO)){
            log.info("【{}】审核结果消息为空！", PinDuoDuoConsts.CHANNEL_NAME);
            return;
        }

        //判断店铺id是否为null
        if (CollectionUtil.isNullOrEmpty(pinDuoDuoShopExamineDTO.getMallIds())) {
            log.info("【{}】拼多多审核结果店铺id为空！", PinDuoDuoConsts.CHANNEL_NAME);
            return;
        }

        //收到消息后暂时不处理
        PinDuoDuoSignShop pinDuoDuoSignShop = new PinDuoDuoSignShop();
        //设置店铺签约状态
        pinDuoDuoSignShop.setSignStatus(pinDuoDuoShopExamineDTO.getSignStatus());
        pinDuoDuoSignShop.setUpdater("系统");
        //设置渠道id
        pinDuoDuoSignShop.setChannelId(pinDuoDuoShopExamineDTO.getChannelId());
        //设置厂商id
        pinDuoDuoSignShop.setFactoryId(pinDuoDuoShopExamineDTO.getFactoryId());

        //每一个店铺都签约通过
        pinDuoDuoShopExamineDTO.getMallIds().forEach(mallId -> {
            pinDuoDuoSignShop.setMallId(mallId);
            pinDuoDuoSignShopService.modifyPinDuoDuoSignShopByMallId(pinDuoDuoSignShop);
        });

    }

    /**
     * 发送消息给拼多多服务
     * @param pathRequest 
     * @param pinDuoDuoSendRequest 
     * @return com.zmn.oms.third.pinduoduo.dto.api.PinDuoDuoResponse
     * @author wangxiaokun
     */
    private PinDuoDuoResponse sendRequestToPinDuoDuo(String pathRequest, PinDuoDuoSendRequest pinDuoDuoSendRequest) {

        // 参数判断
        if (Objects.isNull(pinDuoDuoSendRequest)) {
            return null;
        }

        int sendTimes = 0;
        PinDuoDuoResponse responseRequest = null;

        // 生成签名
        String signRequest = PinDuoDuoUtil.makeRequestSign(pinDuoDuoSendRequest);
        if (Objects.isNull(signRequest) || signRequest.isEmpty()) {
            log.info("【{}-API】 生成签名失败", PinDuoDuoConsts.CHANNEL_NAME);
            return null;
        }

        Map<String, String> map = new HashMap<>(8);
        map.put("type", pinDuoDuoSendRequest.getType());
        map.put("client_id", pinDuoDuoSendRequest.getClient_id());
        map.put("timestamp", pinDuoDuoSendRequest.getTimestamp().toString());
        map.put("partner_id", pinDuoDuoSendRequest.getPartner_id());
        map.put("target_client_id", pinDuoDuoSendRequest.getTarget_client_id());
        map.put("request_id", pinDuoDuoSendRequest.getRequest_id());
        map.put("sign", signRequest);
        map.put("request", pinDuoDuoSendRequest.getRequest());

        // 是否重试
        while (sendTimes < 2) {

            responseRequest = PinDuoDuoUtil.sendRequestToPinDuoDuo(pathRequest, map);
            if (Objects.isNull(responseRequest)) {
                return null;
            }

            // 返回值在100-199之间重试一次
            if (responseRequest.getErrorCode() < 100 || responseRequest.getErrorCode() > 199) {
                return responseRequest;
            }

            sendTimes++;
        }

        return responseRequest;
    }

    /**
     * 保存状态同步结果信息
     * @param orderWorkLogChange 
     * @param orderStatus 
     * @param result 
     * @return void
     * @author wangxiaokun
     */
    private void saveSyncResult(OrderWorkLogChange orderWorkLogChange, int orderStatus, PinDuoDuoResponse result) {
        if (Objects.isNull(result) || Objects.isNull(orderWorkLogChange)) {
            return;
        }

        OrderNotifyLog orderNotifyLog = new OrderNotifyLog();
        orderNotifyLog.setMqMsgKey(orderWorkLogChange.getMqMsgKey());
        orderNotifyLog.setOrderId(orderWorkLogChange.getOrderId());
        orderNotifyLog.setChannelId(orderWorkLogChange.getChannelId());
        orderNotifyLog.setOrderStatus(orderWorkLogChange.getStatus());
        orderNotifyLog.setOrderResultStatus(orderWorkLogChange.getResultStatus());
        orderNotifyLog.setNotifyStatus(String.valueOf(orderStatus));
        orderNotifyLog.setType(OrderConsts.ORDER_NOTIFY_TYPE_CHANGE);
        orderNotifyLog.setNotifyTime(DateUtil.getNow());
        orderNotifyLog.setNotifyResultMsg(String.format("[%s]-%s",
                OrderStatusConsts.getOrderStatusName(orderStatus), result.getErrorMsg()));

        ResultDTO resultDTO = new ResultDTO();
        resultDTO.setStatus(result.getErrorCode() == PinDuoDuoConsts.PDD_RETURN_CODE_SUCCESS ? StatusConsts.STATUS_SUCCESS : StatusConsts.STATUS_ERROR);
        resultDTO.setData(orderNotifyLog);

        orderNotifyLogBService.saveNotifyLog(resultDTO);
    }

    /**
     * 处理拼多多取消订单的请求
     * @param paramsStr 
     * @return void
     * @author wangxiaokun
     */
    protected void parseCancelOrderRequest(String paramsStr) throws OmsBaseException {

        // 获取取消订单的具体内容
        PinDuoDuoCancelOrderParam paramCancelOrder = JSONObject.parseObject(paramsStr, PinDuoDuoCancelOrderParam.class);
        if (Objects.isNull(paramCancelOrder)) {
            throw new OmsBaseException(PinDuoDuoConsts.ZMN_RETURN_CODE_PARAM_ERROR, "解析取消订单参数失败");
        }

        // 查找对应的订单
        String outerId = String.valueOf(paramCancelOrder.getServOrderSn());
        ZsOrderWorkVO orderWorkVO = zsOrderWorkQueryBService.findOrderWorkByOuterId(outerId, null);
        if (Objects.isNull(orderWorkVO)) {
            throw new OmsBaseException(PinDuoDuoConsts.ZMN_RETURN_CODE_PARAM_ERROR,
                    String.format("找不到对应的订单 拼多多服务单号:servOrderSn=[%s]", outerId));
        }

        log.info("【{}】取消订单：订单Id:[{}]，OuterId:[{}]，取消原因:[{}]，扩展信息:[{}]", PinDuoDuoConsts.CHANNEL_NAME,
                orderWorkVO.getOrderId(), outerId, paramCancelOrder.getReason(), paramCancelOrder.getAttributes());

        // 取消订单
        CancelOrderDTO cancelOrderDTO = new CancelOrderDTO();
        cancelOrderDTO.setOrderId(orderWorkVO.getOrderId());
        cancelOrderDTO.setOuterId(outerId);
        cancelOrderDTO.setChannelId(orderWorkVO.getChannelId());
        cancelOrderDTO.setOperatorId((long) orderWorkVO.getChannelId());
        cancelOrderDTO.setOperatorType(GlobalConsts.OPERATE_USER_TYPE_CHANNEL);

        String cancelReason = paramCancelOrder.getReason();

        try {
            cancelOrderDTO.setRemark(cancelReason);
            proxyOrderBService.cancelOrder(cancelOrderDTO);
        } catch (OmsBaseException omsBaseException) {
            log.error("【{}】取消订单失败 消息:[{}]", PinDuoDuoConsts.CHANNEL_NAME, omsBaseException.getMessage());
            throw new OmsBaseException(PinDuoDuoConsts.ZMN_RETURN_CODE_SERVER_ERROR, "取消订单失败");
        }
    }

}
